package com.bonc.ioc.demo.utils;

import com.alibaba.fastjson.JSON;
import com.bonc.ioc.demo.constant.AdministrativeDivisonRule;
import com.bonc.ioc.common.util.CollectionUtil;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;

/**
 * * @description
 *
 * @author jin.xu
 * @date 12/10/20 6:50 PM
 * @change: 12/10/20 6:50 PM by jin.xu for init
 */
@Configuration
public class PermissionsUtil {
    private static StringRedisTemplate redisTemplate;

    @Resource
    private StringRedisTemplate privateRedisTemplate;

    /**
     * 全局的规则缓存
     */
    private static ConcurrentMap<Long, AdministrativeDivisonRule> administrativeDivisonRuleConcurrentMap;
    private static List<AdministrativeDivisonRule> administrativeDivisonRuleList;

    private static Long codeLength;


    /**
     * * @description 初始化权限
     *
     * @return: null
     * @since: 1.0.0
     * @Author: jin.xu
     * @Date: 12/11/20 2:46 PM
     * @change: 12/11/20 2:46 PM by jin.xu for init
     */
    @Bean
    public void initPermissions() {
        PermissionsUtil.redisTemplate = privateRedisTemplate;
        PermissionsUtil.refreshRule();
    }

    public static void refreshRule() {
        if (administrativeDivisonRuleConcurrentMap == null) {
            administrativeDivisonRuleConcurrentMap = new ConcurrentHashMap<>(6);
            administrativeDivisonRuleList = new ArrayList<>();
            codeLength = 0L;
        }

        synchronized (administrativeDivisonRuleConcurrentMap) {
            String dministrativeDivisonRuleKey = "mcp-sys-server:administrative:rule";
            String dministrativeDivisonRuleJson = redisTemplate.opsForValue().get(dministrativeDivisonRuleKey);

            if (StringUtils.isEmpty(dministrativeDivisonRuleJson)) {
                return;
            }

            try {
                administrativeDivisonRuleList =
                                JSON.parseArray(new String(Base64.decodeBase64(dministrativeDivisonRuleJson)),
                                                AdministrativeDivisonRule.class);
            } catch (Exception ex) {
                ex.printStackTrace();
                return;
            }

            if (CollectionUtil.isNotEmpty(administrativeDivisonRuleList)) {
                administrativeDivisonRuleConcurrentMap = new ConcurrentHashMap<>(administrativeDivisonRuleList.size());
                administrativeDivisonRuleConcurrentMap = administrativeDivisonRuleList.stream().collect(
                                Collectors.toConcurrentMap(AdministrativeDivisonRule::getEffectiveLength, t -> t));
                administrativeDivisonRuleList.sort(Comparator.comparing(AdministrativeDivisonRule::getLevelNum,
                                Comparator.nullsFirst(Long::compareTo)));
                codeLength = administrativeDivisonRuleList.stream()
                                .mapToLong(AdministrativeDivisonRule::getEffectivePosition).sum();
            }
        }
    }

    /**
     * * @description
     *
     * @param userAdministrativeDivisionCode: 用户对应的行政区划
     * @param checkAdministrativeDivisionCode: 要校合的行政区划代码
     * @return: true 校合成功 false 校合失败
     * @since: 1.0.0
     * @Author: jin.xu
     * @Date: 12/10/20 6:57 PM
     * @change: 12/10/20 6:57 PM by jin.xu for init
     */
    public static boolean checkPermission(String userAdministrativeDivisionCode,
                    String checkAdministrativeDivisionCode) {

        if (StringUtils.isEmpty(checkAdministrativeDivisionCode)) {
            return false;
        }

        return checkAdministrativeDivisionCode.startsWith(getEffectiveCode(userAdministrativeDivisionCode));
    }

    /**
     * * @description 获取得到该行政区划代码 有效位部分
     *
     * @param administrativeDivisionCode: 行政区划代码
     * @return: 截取后的值
     * @since: 1.0.0
     * @Author: jin.xu
     * @Date: 12/11/20 7:14 PM
     * @change: 12/11/20 7:14 PM by jin.xu for init
     */
    public static String getEffectiveCode(String administrativeDivisionCode) {

        if (StringUtils.isEmpty(administrativeDivisionCode)) {
            return administrativeDivisionCode;
        }

        AdministrativeDivisonRule administrativeDivisonRule = getAdministrativeDivisonRule(administrativeDivisionCode);

        if (administrativeDivisonRule == null) {
            return administrativeDivisionCode;
        }

        String temp = null;
        if (administrativeDivisionCode.length() < administrativeDivisonRule.getEffectiveLength().intValue()) {
            temp = StringUtils.rightPad(administrativeDivisionCode,
                            administrativeDivisonRule.getEffectiveLength().intValue(), "0");
        } else {
            temp = administrativeDivisionCode.substring(0, administrativeDivisonRule.getEffectiveLength().intValue());
        }
        return temp;
    }


    /**
     * * @description 获取行政级别代码规则
     *
     * @param administrativeDivisionCode: 行政级别代码
     * @return: 获取到的行政级别代码规则
     * @since: 1.0.0
     * @Author: jin.xu
     * @Date: 12/10/20 9:53 PM
     * @change: 12/10/20 9:53 PM by jin.xu for init
     */
    public static AdministrativeDivisonRule getAdministrativeDivisonRule(String administrativeDivisionCode) {
        if (StringUtils.isEmpty(administrativeDivisionCode)) {
            // 如果字符串为空 则认为没有规则
            return null;
        }

        if (CollectionUtil.isEmpty(administrativeDivisonRuleList)) {
            return null;
        }

        // 先筛选职责 按职责的位数获取对应规则
        List<AdministrativeDivisonRule> administrativeDivisonRules = administrativeDivisonRuleList.stream()
                        .filter(t -> t.getEffectiveLength() <= administrativeDivisionCode.length())
                        .collect(Collectors.toList());

        if (CollectionUtil.isEmpty(administrativeDivisonRules)) {
            return null;
        }

        AdministrativeDivisonRule administrativeDivisonRule;
        Long beginIdx = 0L;
        Long endIdx = 0L;

        int startIdx = administrativeDivisonRules.size() - 1;

        if (administrativeDivisionCode.length() > administrativeDivisonRules.get(startIdx).getEffectiveLength()) {
            startIdx++;
        }

        if (administrativeDivisonRuleList.size() <= startIdx) {
            startIdx = administrativeDivisonRuleList.size() - 1;
        }

        // 注意：此处循环administrativeDivisonRules 从 administrativeDivisonRuleList中取值 原因是因为两个集和的顺序一样并且按长度筛选后还要夺取
        for (int idx = startIdx; idx >= 0; idx--) {
            if (idx == 0) {
                beginIdx = 0L;
            } else {
                beginIdx = administrativeDivisonRuleList.get(idx - 1).getEffectiveLength();
            }

            administrativeDivisonRule = administrativeDivisonRuleList.get(idx);
            endIdx = administrativeDivisonRule.getEffectiveLength();

            // 判断是否有效位 如果全部为0说明是无效位
            String temp = null;
            if (administrativeDivisionCode.length() < endIdx) {
                temp = administrativeDivisionCode.substring(beginIdx.intValue());
                temp = StringUtils.rightPad(temp, administrativeDivisonRule.getEffectivePosition().intValue(), "0");
            } else {
                temp = administrativeDivisionCode.substring(beginIdx.intValue(), endIdx.intValue());
            }

            if (!temp.equals(administrativeDivisonRule.getInvalidCharacter())) {
                return administrativeDivisonRule;
            }
        }

        return null;
    }
}
